<?php

/**
 * QEvents 管理整个应用程序的回调方法，实现全局的事件驱动
 */
class QEvents {

    /**
     * 所有已经注册的回调方法
     *
     * @var array of callback
     */
    static private $_events = array();

    /**
     * 添加一个新的回调方法，并返回方法的索引
     *
     * @code php
     * $index = $this->on('app::startup', $callback);
     * @endcode
     *
     * @param string $id 要注册的 ID
     * @param callback $callback 时间回调方法
     * @param array $params 提供给回调方法的附加参数
     *
     * @return int 新添加方法的索引
     */
    public function on($id, $callback, $params = array()) {
        self::$_events[$id][] = array($callback, $params);
        return count(self::$_events[$id]) - 1;
    }

    /**
     * 注销一个回调方法，并返回被注销的回调方法
     *
     * @code php
     * $index = $this->on('app::startup', $callback);
     * ......
     * $callback = $this->un('app::startup', $index);
     * @endcode
     *
     * 如果没有提供 $index 参数，则注销同名 ID 最后注册的一个方法。
     *
     * 如果指定 ID 没有回调方法或指定的 $index 参数无效，则返回 null。
     *
     * @param string $id 要注销的 ID
     * @param int $index 索引
     *
     * @return callback
     */
    public function un($id, $index = null) {
        if (!isset(self::$_events[$id]))
            return null;
        if (is_null($index)) {
            return array_pop(self::$_events[$id]);
        } elseif (!isset(self::$_events[$id][$index])) {
            return null;
        }
        $callback = self::$_events[$id][$index];
        unset(self::$_events[$id][$index]);
        return $callback;
    }
    /**
     * 检查指定 ID 是否注册了回调方法
     *
     * @param string $id 要检查的 ID
     *
     * @return boolean
     */
    public function check($id) {
        return !empty(self::$_events[$id]);
    }

    /**
     * 调用指定 ID 的回调方法，并返回结果,参数个数不限定
     *
     * @code php
     * $return = $this->fire('app::startup');
     * var_dump($return);
     * @endcode
     *
     * 由于同一 ID 可能注册多个回调方法，因此 $return 将是一个数组。
     * 以回调方法的索引为 $return 数组的键名，该回调方法的返回结果为键值。
     *
     * @param string $id 要调用的 ID
     * @param array $params 传递给回调方法的参数
     *
     * @return array
     */
    public function fire($id) {
        if (!isset(self::$_events[$id]))
            return null;

        $return = array();
        $params = func_get_args();
        array_shift($params);
        while (list($index, $callback) = each(self::$_events[$id])) {
            $return[$index] = call_user_func_array($callback[0], $params);
//            $return[$index] = call_user_func_array($callback[0], array($params,(array)$callback[1]));
        }

        return $return;
    }

    static function instance() {
        static $instance;
        if (is_null($instance)) {
            $instance = new QEvents();
        }
        return $instance;
    }
}

